﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace code_helper
{
    class codeWFL
    {
        public enum CODE_TYPE
        {
            NOTE_LINE = 1,
            NOTE_SECTOR = 2,
            CODETEXT = 3,
        };
        public struct codeUnit
        {
            public CODE_TYPE type;
            public bool isNote;
            public string text;
        }
        

        #region state machine
        public enum CODE_STATE
        {
            SM_normal = 0,
            SM_XG = 1,                  //      /
            SM_XG_XX = 2,               //      /*
            SM_XG_XX_XX = 3,            //      /*  *
            SM_XG_XG = 4,               //      //
            SM_XG_XG_CO = 5,            //      //  \
            SM_DY = 6,                  //      '
            SM_DY_CO = 7,               //      '\
            SM_SY = 8,                  //      "
            SM_SY_CO = 9,               //      "\

        }
        static string getcodestring(string srcstr)
        {
            string ret = "";

            char c;
            char[] allc = srcstr.ToCharArray();

            int  state = 0;
            int count = 0;

            while (count < allc.Length)
            {
                c = allc[count];
                count++;

                switch (state)
                {
                    case 0:
                        if (c == '/')// ex. [/]  
                            state = 1;
                        else if (c == '\'')// ex. [']  
                            state = 6;
                        else if (c == '\"')// ex. ["]  
                            state = 8;
                        else
                            ret += c;
                        break;
                    case 1:
                        if (c == '*')// ex. [/*]  
                            state = 2;
                        else if (c == '/')// ex. [//]  
                            state = 4;
                        else
                        { // ex. [<secure/_stdio.h> or 5/3]  
                            ret += '/';
                            ret += c;
                            state = 0;
                        }
                        break;
                    case 2:
                        if (c == '*') // ex. [/*he*]  
                            state = 3;
                        else // ex. [/*heh]  
                            state = 2;
                        break;
                    case 3:
                        if (c == '/')// ex. [/*heh*/]  
                            state = 0;
                        else if (c == '*')
                            state = 3;//ex. [/***]注意这里，不加这个条件，*的个数是奇数的时候出错  
                        else// ex. [/*heh*e]  
                            state = 2;
                        break;
                    case 4:
                        if (c == '\\')// ex. [//hehe\]  
                            state = 5;
                        else if (c == '\n')// ex. [//hehe<enter>]  
                        {
                            state = 0;
                            ret += '\r';  //for window system, adding '\r',which don't need in unix system.
                            ret += c;
                        }
                        break;
                    case 5:
                        if (c == '\\')// ex. [//hehe\\\\\]  
                            state = 5;
                        else// ex. [//hehe\<enter> or //hehe\a]  
                            state = 4;
                        break;
                    case 6:
                        if (c == '\\')// ex. ['\]  
                            state = 7;
                        else if (c == '\'')// ex. ['\n' or '\'' or '\t' ect.]  
                        {
                            state = 0;
                            ret += c;
                        }
                        break;
                    case 7:// ex. ['\n or '\' or '\t etc.]  
                        state = 6;
                        break;
                    case 8:
                        if (c == '\\')// ex. ["\]  
                            state = 9;
                        else if (c == '\"')// ex. ["\n" or "\"" or "\t" ect.]  
                        {
                            state = 0;
                            ret += c;
                        }
                        break;
                    case 9:// ex. ["\n or "\" or "\t ect.]  
                        state = 8;
                        break;
                }
                if (state == 6 || state == 7 || state == 8 || state == 9)
                    ret += c;
            }
            return ret;
        }
        #endregion

        static public codeUnit[] codeSplit(string srcCode)
        {
            ArrayList part = new ArrayList();
            part.Clear();

            codeUnit temp;
            while( (srcCode.Contains("/*") && srcCode.Contains("*/")) || srcCode.Contains("//"))
            {
                int a = srcCode.IndexOf("/*");
                int b = srcCode.IndexOf("*/");
                int c = srcCode.IndexOf("//");

                #region hand "//" that before "/* */"
                if ((c < a || a==-1) && c != -1)
                {
                    if (c > 0)
                    {
                        temp.text = srcCode.Substring(0, c);
                        temp.isNote = false;
                        temp.type = CODE_TYPE.CODETEXT;
                        part.Add(temp);
                        srcCode = srcCode.Substring(c);
                    }
                    int d = srcCode.IndexOf("\r\n");
                    if (d == -1)
                    {
                        temp.text = srcCode;
                        temp.isNote = true;
                        temp.type = CODE_TYPE.NOTE_LINE;
                        part.Add(temp);
                        srcCode = "";
                        break;
                    }
                    else
                    {
                        temp.text = srcCode.Substring(0, d);
                        temp.isNote = true;
                        temp.type = CODE_TYPE.NOTE_LINE;
                        part.Add(temp);
                        srcCode = srcCode.Substring(d);
                    }
                    continue;
                }
                #endregion

                #region handle "/* */"
                if (a == -1 || b == -1)
                    break;

                if (a + 2 > b)
                    break;

                if (a > 0)
                {
                    temp.text = srcCode.Substring(0, a);
                    temp.isNote = false;
                    temp.type = CODE_TYPE.CODETEXT;
                    part.Add(temp);
                }
                temp.text = srcCode.Substring(a, b + 2 - a);
                temp.isNote = true;
                temp.type = CODE_TYPE.NOTE_SECTOR;
                part.Add(temp);
                srcCode = srcCode.Substring(b + 2);
                #endregion
            }
            temp.text = srcCode;
            temp.isNote = false;
            temp.type = CODE_TYPE.CODETEXT;
            part.Add(temp);

            #region return string
            if (part.Count == 0)
                return null;
            codeUnit[] codes = new codeUnit[part.Count];
            for (int i = 0; i < codes.Length; i++)
            {
                codes[i] = (codeUnit)part[i];
            }
            return codes;
            #endregion
        }
        static public string codeDeleteNote(string srcCode,string greptext)
        {
            string ret = "";

            codeUnit[] codes = codeSplit(srcCode);
            if (codes == null)
                return "";
            for (int i = 0; i < codes.Length; i++)
            {
                if (codes[i].type == CODE_TYPE.CODETEXT)
                    ret += codes[i].text;
                else if (!codes[i].text.Contains(greptext))
                    ret += codes[i].text;
            }

            //string smstring = getcodestring(srcCode);
            //if (smstring != ret)
            //    return smstring;


            return ret;
        }
    //--------------------------------------------------------------------
    }
}
